<template>
    <div class="main">
        <div ref="sceneNode" class="scene">
        </div>
    </div>
</template>

<script setup name="ModelView">
/**
 * @author zhaojiuyi
 * @date 2023/6/22
 * */
import {
    AmbientLight,
    WebGLRenderer,
    Mesh,
    Clock,
    Scene,
    PerspectiveCamera,
    PointLight,
    PointLightHelper,
    MeshBasicMaterial,
    BackSide,
    SphereGeometry,
    AnimationMixer,
    TextureLoader
} from "three"
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
import {onMounted, onUnmounted, ref} from "vue";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";


let timer = null
let gblModel = null
let animationMixer= null
const sceneNode = ref()

// 渲染器
const renderer = new WebGLRenderer({antialias: true})
renderer.shadowMap.enabled = true

// 场景
const scene = new Scene()
// scene.fog = new Fog(0xcccccc, 5, 100);

// 相机
const camera = new PerspectiveCamera()
camera.position.set(50,20,50)

// 环境光
const ambientLight = new AmbientLight(0xffffff, 1); // 柔和的白光
scene.add(ambientLight);

// 点光源
// const pointLight = new PointLight(0xffffff, 5, 80);
// pointLight.position.set(0, 40, 10);
// pointLight.castShadow = true
// pointLight.shadow.mapSize.width = 5000
// pointLight.shadow.mapSize.height = 5000
// pointLight.shadow.camera.near = 0.5
// pointLight.shadow.camera.far = 5
// scene.add(pointLight);

// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
controls.minDistance = 10
controls.maxDistance = 500

// 创建一个立方体几何体
const skyBoxGeometry = new SphereGeometry( 500, 32, 16 );
// 创建一个纹理对象
const texture = new TextureLoader().load('http://localhost:8080/env1.jpg');
// 创建一个材质对象
const skyBoxMaterial = new MeshBasicMaterial({map: texture, side: BackSide});
// 创建一个网格对象
const skyBox = new Mesh(skyBoxGeometry, skyBoxMaterial);
skyBox.castShadow = true
skyBox.receiveShadow = true
// 将网格对象添加到场景中
scene.add(skyBox);


// 时钟
const clock = new Clock()
const render = () => {
    renderer.render(scene, camera)
    controls.update();
    if (animationMixer) {
        animationMixer.update(clock.getDelta())
    }
    timer = requestAnimationFrame(render)
}

const createModel = () => {
    const loader = new GLTFLoader()
    return new Promise((resolve, reject) => {
        loader.load('/models/Parrot.glb', glb => {
                resolve(glb)
            }, () => {
            },
            err => {
                reject()
            })
    })
}

onMounted(async () => {
    const sceneDom = sceneNode.value
    renderer.setSize(sceneDom.clientWidth, sceneDom.clientHeight)
    sceneDom.innerHTML = null
    sceneDom.appendChild(renderer.domElement)

    gblModel = await createModel()
    gblModel.scene.position.set(0,20,0)
    gblModel.scene.traverse(e => {
        if (e.isMesh) {
            e.castShadow = true
            e.receiveShadow = true
        }
    })
    scene.add(gblModel.scene)
    animationMixer = new AnimationMixer(gblModel.scene)
    animationMixer.clipAction(gblModel.animations[0]).play()
    render()
})

onUnmounted(() => {
    cancelAnimationFrame(timer)
})

const onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.render(scene, camera);
}

window.addEventListener("resize",onWindowResize)


</script>
<style>
.main {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    display: flex;

}

.scene {
    flex-grow: 3;
    flex-shrink: 0;
    flex-basis: 0;
}

.control {
    flex-grow: 1;
    flex-shrink: 0;
    flex-basis: 0;
}
</style>

